package numatopo

import (
	"context"
	"fmt"
	"os"
	"time"

	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/klog"

	"volcano.sh/apis/pkg/apis/nodeinfo/v1alpha1"
	"volcano.sh/apis/pkg/client/clientset/versioned"
	"volcano.sh/resource-exporter/pkg/args"
)

// NodeInfoRefresh check the data changes
func NodeInfoRefresh(opt *args.Argument) bool {
	isChange := false

	klConfig, err := GetKubeletConfigFromLocalFile(opt.KubeletConf)
	if err != nil {
		klog.Errorf("failed to get kubelet configuration, err: %v", err)
	} else {
		isChange = TryUpdatingResourceReservation(klConfig, opt.ResReserved)
	}

	return isChange || TopoInfoUpdate(opt)
}

// CreateOrUpdateNumatopo create or update the numatopo to etcd
func CreateOrUpdateNumatopo(client *versioned.Clientset) {
	hostname := os.Getenv("MY_NODE_NAME")
	if hostname == "" {
		klog.Errorf("Get env MY_NODE_NAME failed.")
		return
	}

	numaInfo, err := client.NodeinfoV1alpha1().Numatopologies().Get(context.TODO(), hostname, metav1.GetOptions{})
	if err != nil {
		if !apierrors.IsNotFound(err) {
			klog.Errorf("Get Numatopo for node %s failed, err=%v", hostname, err)
			return
		}

		numaInfo = &v1alpha1.Numatopology{
			ObjectMeta: metav1.ObjectMeta{
				Name: hostname,
			},
			Spec: v1alpha1.NumatopoSpec{
				Policies:    GetPolicy(),
				ResReserved: GetResReserved(),
				NumaResMap:  GetAllResAllocatableInfo(),
				CPUDetail:   GetCpusDetail(),
			},
		}

		_, err = client.NodeinfoV1alpha1().Numatopologies().Create(context.TODO(), numaInfo, metav1.CreateOptions{})
		if err != nil {
			klog.Errorf("Create Numatopo for node %s failed, err=%v", hostname, err)
		}
	} else {
		numaInfo.Spec = v1alpha1.NumatopoSpec{
			Policies:    GetPolicy(),
			ResReserved: GetResReserved(),
			NumaResMap:  GetAllResAllocatableInfo(),
			CPUDetail:   GetCpusDetail(),
		}
		if numaInfo.Annotations == nil {
			numaInfo.Annotations = make(map[string]string)
		}
		// use to trigger CR numa update
		numaInfo.Annotations["timestamp"] = fmt.Sprint(time.Now().Unix())

		_, err = client.NodeinfoV1alpha1().Numatopologies().Update(context.TODO(), numaInfo, metav1.UpdateOptions{})
		if err != nil {
			klog.Errorf("Update Numatopo for node %s failed, err=%v", hostname, err)
		}
	}
}
